package org.sidora.core;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;


import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.query.Predicate;
import org.sidora.core.util.AbstractFactory;
import org.sidora.core.util.AbstractInventory;
import org.sidora.core.util.OCProvider;
import org.sidora.core.util.ParameterCollector;

/**
 * Describer
 * @author Enric Tartera, Juan Manuel Gimeno, Roger Masgoret
 * @version 1.0
 */
public class Describer implements  Comparable, Serializable {
    
    private String label; //etiqueta tipus
    private Site site;
    private Class referencedClass; //stratum
    private Field field;
    
    //private TreeSet<Category> categories = new TreeSet<Category>();
    
    private Describer(){}
    
    public Class getReferencedClass() {
        return referencedClass;
    }
    public void setReferencedClass(Class referencedClass) {
        this.referencedClass = referencedClass;
    }
    
    public String getLabel() {
        return label;
    }
    public void setLabel(String label) {
        this.label = label;
    }
    
    public Field getField() {
        return field;
    }
    
    
    public void setField(Field field) {
        this.field = field;
    }
    
    
    public boolean equals(Object obj) {
        if (obj == this)	return true;
        
        if (!(obj instanceof Describer)) return false;
        
        Describer cat = null;
        try {
            cat = (Describer) obj;
        } catch (Exception e) {
            return false;
        }
        if (!(this.label.equals(cat.label)&&
                this.referencedClass.equals(cat.referencedClass))) return false;
        return true;
    }
    
    
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return this.label;
    }
    
    
    
    
    
    
    public static class Inventory extends AbstractInventory{
        
        public boolean exist(final Describer cat) throws Exception{
            ObjectContainer db = OCProvider.getInstance();
            ObjectSet<Describer> categories = db.query(new Predicate<Describer>() {
                
                public boolean match(Describer candidate) {
                    return candidate.equals(cat);
                }
            });
            
            if (categories.hasNext()){
                return true;
            } else {
                return false;
            }
        }
        
        public Describer getNewObject(ParameterCollector param) throws Exception{
            Describer type = new Describer();
            type.setLabel((String) param.get("label"));
            type.setSite((Site) param.get("site"));
            type.setField((Field) param.get("field"));
            type.setReferencedClass((Class) param.get("class"));
            
            return type;
        }
        
        
        
        
        public Object getObject(ParameterCollector param) {
//		Carrega la Actuaci� amb el corresponent id
            
            final String key = (String) param.get("label");
            ObjectContainer db = OCProvider.getInstance();
            ObjectSet <Describer> types = db.query(new Predicate <Describer>() {
                public boolean match(Describer atype) {
                    return (atype.label.equals(key));
                }
            });
            
            
            if (types.hasNext()){
                return types.next();
            } else throw new RuntimeException("Tipus inexistent");
        }
        
        @Override
        protected KeyObject getNewKey(ParameterCollector param) {
            // TODO Auto-generated method stub
            return null;
        }
        
        public static List getList() {
            ObjectContainer db = OCProvider.getInstance();
            List<Describer> list = db.query(Describer.class);
            
            return list;
        }
        
        public static List<Describer> getList(final Site site) {
            ObjectContainer db = OCProvider.getInstance();
            List<Describer> list = db.query(new Predicate<Describer>(){
                
                @Override
                public boolean match(Describer categoryType) {
                    // TODO Auto-generated method stub
                    return categoryType.getSite()==site;
                }});
                db.commit();
                return list;
        }
        
        public static List<Describer> getList(final Site site, final Class classA, final Field field) {
            ObjectContainer db = OCProvider.getInstance();
            List<Describer> list = db.query(new Predicate<Describer>(){
                
                @Override
                public boolean match(Describer describer) {
                    // TODO Auto-generated method stub
                    return ((describer.getSite()==site) && (describer.getClass()==classA) && (describer.getField().getName().equals(field.getName())));
                }});
                db.commit();
                return list;
        }
        
        public static List<Describer> getList(final Class classA) {
            ObjectContainer db = OCProvider.getInstance();
            List<Describer> list = db.query(new Predicate<Describer>(){
                
                @Override
                public boolean match(Describer describer) {
                    // TODO Auto-generated method stub
                    return describer.getClass()==classA;
                }});
                db.commit();
                return list;
        }
        
        public static List<Describer> getList(final Field field) {
            ObjectContainer db = OCProvider.getInstance();
            List<Describer> list = db.query(new Predicate<Describer>(){
                
                @Override
                public boolean match(Describer describer) {
                    // TODO Auto-generated method stub
                    return describer.getField() == field;
                }});
                db.commit();
                return list;
        }
        
    }
    
    public int compareTo(Object obj) {
        Describer type = (Describer) obj;

        if (this.referencedClass.getCanonicalName().compareTo(type.referencedClass.getCanonicalName())!= 0)
            return this.referencedClass.getCanonicalName().compareTo(type.referencedClass.getCanonicalName());
        else return this.label.compareTo(type.label);
    }
    
    public Site getSite() {
        return site;
    }
    
    public void setSite(Site site){
        this.site = site;
    }

    
}
